
/* verilator lint_off UNDRIVEN */
/* verilator lint_off UNUSED */
/* verilator lint_off EOFNEWLINE */
`include "defines.v"
`include "if_stage.v"
`include "id_stage.v"
`include "exe_stage.v"
`include "mem_stage.v"
`include "wb_stage.v"
`include "ff.v"

module rvcpu(
    input wire            clk,
    input wire            rst,
    input wire  [`INS_BUS-1 : 0] inst,
    input wire  [`REG_BUS-1 : 0] dmem_r_data,
    
    output wire [`REG_BUS-1 : 0] inst_addr,

    output wire [`REG_BUS-1 : 0] dmem_r_addr,
    output wire                  dmem_r_ena,
    output wire                  dmem_w_ena,
    output wire [`REG_BUS-1 : 0] dmem_w_addr,
    output wire [`REG_BUS-1 : 0] dmem_w_data,
    output wire                  inst_ena,
    output wire is_x9
);

    assign is_x9 = w_rd_ena_wb_id & (rd_wb_id==5'd9);

    if_stage IF(
            .clk(clk),
            .rst(rst),
            .inst_i(inst),
            .stall(stall_exe[3] | stall_mem | stall_id),//(is_jal_if_id & is_B_id_ex)
            .stall_exe(stall_exe[3]),
            .stall_mem(stall_mem),
            .stall_id(stall_id),
            .pc_plus_i(pc_plus_mem_if),
            .flush_i(flush_mem),
            .is_B_jump_i(is_B_jump_ex_mem & is_B_ex_mem),
            .pc_plus_ID_i(pc_plus_if_id),
            .is_jal_i(is_jal_if_id & (~flush_delay_if_id)),
            .is_jalr_mem_i(is_jalr_ex_mem),
            .jalr_pc_i(jalr_pc_mem_if),

            .inst_addr(inst_addr),
            .inst_o(inst_if_id),
            .inst_ena(inst_ena),
            .flush_delay(flush_delay_if_id),
            .pc_MEM_o(pc_plus_4_wb_if),
            .pc_ID_o(pc_ID_if_exe)
             );

    // IF<>ID
    wire [`INS_BUS-1 : 0] inst_if_id;
    wire                  flush_delay_if_id;
    wire [`REG_BUS-1 : 0] pc_plus_if_id;
    wire                  is_jal_if_id;

    wire stall_id;

    id_stage ID(
            .clk(clk),
            .rst(rst),
            .inst_i(inst_if_id),
            .regfile_w_ena(w_rd_ena_wb_id),
            .regfile_w_addr(rd_wb_id),
            .regfile_w_data(wb_data_wb_id),
            .stall(stall_exe[2] | stall_mem),
            .flush_i(flush_mem),
            .flush_delay_i(flush_delay_if_id),
            .is_B_id_ex(is_B_id_ex),
    
            .op1(op1_id_ex),
            .op2(op2_id_ex),
            .rd(rd_id_ex),
            .w_rd_ena(w_rd_ena_id_ex),
            .load_ena(load_ena_id_ex),
            .store_ena(store_ena_id_ex),
            .load_store_bytes(load_store_bytes_id_ex),
            .mode_ALU(mode_ALU_id_ex),
            .n_bytes_ALU(n_bytes_id_ex),
            .is_AL_OP(is_AL_OP_id_ex),
            .is_I_AL_OP_o(is_I_AL_OP_id_ex),
            .rs1(rs1_id_ex),
            .rs2(rs2_id_ex),
            .rs2_data_o(rs2_data_id_ex),
            .is_B_o(is_B_id_ex),
            .is_auipc_o(is_auipc_id_ex),
            .is_lui_o(is_lui_id_ex),
            .pc_plus(pc_plus_id_ex),
            .is_jal_o(is_jal_id_ex),
            .is_jalr_o(is_jalr_id_ex),
            .is_jal_IF_o(is_jal_if_id),
            .pc_plus_IF_o(pc_plus_if_id),
            .stall_o(stall_id)
             );

    // ID<>EX
    wire [3:0] mode_ALU_id_ex;
    wire [1:0] n_bytes_id_ex;
    wire [4:0] rd_id_ex;
    wire       w_rd_ena_id_ex;
    wire [`REG_BUS-1 : 0] op1_id_ex, op2_id_ex;
    wire [4:0] rs1_id_ex, rs2_id_ex;
    wire       load_ena_id_ex;
    wire [2:0] load_store_bytes_id_ex;
    wire       is_AL_OP_id_ex;
    wire       is_I_AL_OP_id_ex;
    wire       store_ena_id_ex;
    wire [`REG_BUS-1 : 0] rs2_data_id_ex;
    wire [`REG_BUS-1 : 0] pc_plus_id_ex;
    wire                  is_B_id_ex;
    wire                  is_jal_id_ex;
    wire                  is_jalr_id_ex;
    wire                  is_auipc_id_ex;
    wire                  is_lui_id_ex;
    wire [`REG_BUS-1 : 0] pc_ID_if_exe;

    //data hazard
    wire [3:0] stall_exe;


    exe_stage EX(
            .clk(clk),
            .rst(rst),
            .mode_ALU(mode_ALU_id_ex),
            .n_bytes_ALU(n_bytes_id_ex),
            .op1_alu(op1_id_ex),
            .op2_alu(op2_id_ex),
            .rd(rd_id_ex),
            .w_rd_ena(w_rd_ena_id_ex),
            .rs1(rs1_id_ex),
            .rs2(rs2_id_ex),
            .load_ena_i(load_ena_id_ex),
            .store_ena_i(store_ena_id_ex),
            .load_store_bytes_i(load_store_bytes_id_ex),
            .rs2_data_i(rs2_data_id_ex),
            .is_B_i(is_B_id_ex),
            .is_auipc_i(is_auipc_id_ex),
            .is_lui_i(is_lui_id_ex),
            .is_jal_i(is_jal_id_ex),
            .is_jalr_i(is_jalr_id_ex),
            .pc_plus_i(pc_plus_id_ex),
            .flush_i(flush_mem),
            .pc_ID_i(pc_ID_if_exe),

            .rd_mem_wb(rd_mem_wb),
            .wb_data_mem_wb(wb_data_wb_id),
            .wb_ena_mem_wb(w_rd_ena_mem_wb),
            .rd_ex_mem(rd_ex_mem),
            .wb_data_ex_mem(result_ALU_ex_mem),
            .wb_ena_ex_mem(w_rd_ena_ex_mem),
            .is_AL_OP_i(is_AL_OP_id_ex),
            .is_AL_OP_ex_mem(is_AL_OP_ex_mem),
            .is_AL_OP_mem(is_AL_OP_mem),
            .is_I_AL_OP(is_I_AL_OP_id_ex),
            .stall_i(stall_mem),
            .is_jal_o(is_jal_ex_mem),
            .is_jalr_o(is_jalr_ex_mem),
            .is_U_o(is_U_ex_mem),

            .load_ena_o(load_ena_ex_mem),
            .store_ena_o(store_ena_ex_mem),
            .load_store_bytes_o(load_store_bytes_ex_mem),
            .rd_o(rd_ex_mem),
            .w_rd_ena_o(w_rd_ena_ex_mem),
            .result_ALU(result_ALU_ex_mem),
            .is_AL_OP_o(is_AL_OP_ex_mem),
            .stall_o(stall_exe), // load-use data hazard
            .rs2_data_o(rs2_data_ex_mem),
            .is_B_o(is_B_ex_mem),
            .pc_plus_o(pc_plus_ex_mem),
            .is_B_jump_o(is_B_jump_ex_mem)
             );
    
    // EX<>MEM
    wire [`REG_BUS-1 : 0] result_ALU_ex_mem;
    wire [`REG_BUS-1 : 0] rs2_data_ex_mem;
    wire [4:0] rd_ex_mem;
    wire       w_rd_ena_ex_mem;
    wire       load_ena_ex_mem;
    wire [2:0] load_store_bytes_ex_mem;
    wire       is_AL_OP_ex_mem;
    wire       is_AL_OP_mem;
    wire       store_ena_ex_mem;
    wire       is_B_ex_mem;
    wire       is_B_jump_ex_mem;
    wire [`REG_BUS-1 : 0] pc_plus_ex_mem;
    wire stall_mem;
    wire flush_mem;
    wire [`REG_BUS-1 : 0] pc_plus_mem_if;
    wire is_jal_ex_mem;
    wire is_jalr_ex_mem;
    wire [`REG_BUS-1 : 0] jalr_pc_mem_if;
    wire  is_U_ex_mem;

    mem_stage MEM(
            .clk(clk),
            .rst(rst), 
            .result_ALU(result_ALU_ex_mem),
            .rd(rd_ex_mem),
            .w_rd_ena(w_rd_ena_ex_mem),
            .load_ena_i(load_ena_ex_mem),
            .store_ena_i(store_ena_ex_mem),
            .load_store_bytes_i(load_store_bytes_ex_mem),
            .dmem_r_data(dmem_r_data),
            .is_AL_OP_i(is_AL_OP_ex_mem),
            .rs2_data_i(rs2_data_ex_mem),
            .is_B_i(is_B_ex_mem),
            .is_U_i(is_U_ex_mem),
            .pc_plus_i(pc_plus_ex_mem),
            .is_B_jump_i(is_B_jump_ex_mem),
            .is_jal_i(is_jal_ex_mem),
            .is_jalr_i(is_jalr_ex_mem),
            
            .rd_o(rd_mem_wb),
            .w_rd_ena_o(w_rd_ena_mem_wb),
            .wb_data(wb_data_mem_wb),
            .wb_data_1(wb_data_1_mem_wb),
            .result_ALU_o(result_ALU_mem_wb),
            .load_ena_o(load_ena_mem_wb),
            .dmem_r_ena(dmem_r_ena),
            .dmem_r_addr(dmem_r_addr),
            .dmem_w_ena(dmem_w_ena),
            .dmem_w_addr(dmem_w_addr),
            .dmem_w_data(dmem_w_data),
            .is_AL_OP_o(is_AL_OP_mem),
            .is_misalign(is_misalign_mem_wb),
            .stall(stall_mem),
            .r_addr_2_0(r_addr_2_0_mem_wb),
            .load_store_bytes_o(load_store_bytes_mem_wb),
            .pc_plus_o(pc_plus_mem_if),
            .flush(flush_mem),
            .is_jal_o(is_jal_mem_wb),
            .is_jalr_o(is_jalr_mem_wb),
            .jalr_pc_o(jalr_pc_mem_if),
            .is_U_o(is_U_mem_wb)
             );

    // MEM<>WB
    wire [`REG_BUS-1 : 0] wb_data_mem_wb, wb_data_1_mem_wb;
    wire [4:0] rd_mem_wb;
    wire       w_rd_ena_mem_wb;
    wire       load_ena_mem_wb;
    wire [`REG_BUS-1 : 0] result_ALU_mem_wb;
    //WB<>ID
    wire [`REG_BUS-1 : 0] wb_data_wb_id;
    wire [4:0] rd_wb_id;
    wire       w_rd_ena_wb_id;
    wire [2:0] r_addr_2_0_mem_wb;
    wire       is_misalign_mem_wb;
    wire [2:0] load_store_bytes_mem_wb;
    wire [`REG_BUS-1 : 0] pc_plus_4_wb_if;
    wire is_jal_mem_wb;
    wire is_jalr_mem_wb;
    wire  is_U_mem_wb;

    wb_stage WB(
            // .clk(clk),
            // .rst(rst), 
            .wb_data(wb_data_mem_wb),
            .wb_data_1(wb_data_1_mem_wb),
            .result_ALU(result_ALU_mem_wb),
            .load_ena_i(load_ena_mem_wb),
            .rd(rd_mem_wb),
            .w_rd_ena(w_rd_ena_mem_wb),
            .is_misalign(is_misalign_mem_wb),
            .r_addr_2_0(r_addr_2_0_mem_wb),
            .load_store_bytes_i(load_store_bytes_mem_wb),
            .pc_plus_4_i(pc_plus_4_wb_if),
            .is_jal_i(is_jal_mem_wb),
            .is_jalr_i(is_jalr_mem_wb),
            .is_U_i(is_U_mem_wb),
            
            .wb_data_o(wb_data_wb_id),
            .rd_o(rd_wb_id),
            .w_ena_o(w_rd_ena_wb_id)  );


endmodule
